﻿using Sgr.Domain.Entities;
using Sgr.Domain.Repositories;
using Sgr.Exceptions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.Domain.Managers
{
    public abstract class TreeNodeManageBase<TEntity, TPrimaryKey> : ITreeNodeManage<TEntity, TPrimaryKey>
        where TEntity : class, IEntity<TPrimaryKey>, ITreeNode<TPrimaryKey>, IAggregateRoot
    {
        protected readonly ITreeNodeBaseRepositoryOfTEntityAndTPrimaryKey<TEntity, TPrimaryKey> _repository;

        public TreeNodeManageBase(ITreeNodeBaseRepositoryOfTEntityAndTPrimaryKey<TEntity, TPrimaryKey> repository)
        {
            _repository = repository;
        }

        /// <summary>
        /// 删除节点及其子节点
        /// </summary>
        /// <param name="id">要删除的节点ID</param>
        /// <param name="isCascade">是否级联删除子节点</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>删除结果</returns>
        public virtual async Task<bool> RemoveNodeAsync(
            TPrimaryKey id,
            bool isCascade = true,
            CancellationToken cancellationToken = default)
        {
            var entity = await _repository.GetAsync(id, cancellationToken);
            if (entity == null)
                return false;

            return await RemoveNodeAsync(entity, isCascade, cancellationToken);
        }

        /// <summary>
        /// 删除节点及其子节点
        /// </summary>
        /// <param name="entity">节点</param>
        /// <param name="isCascade">是否级联删除子节点</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>删除结果</returns>
        public virtual async Task<bool> RemoveNodeAsync(
            TEntity entity,
            bool isCascade = true,
            CancellationToken cancellationToken = default)
        {
            if (isCascade)
            {
                // 级联删除子节点
                var sons = await _repository.GetChildNodesRecursionAsync(entity, cancellationToken);
                foreach (var son in sons)
                {
                    BeforeDeleteEntity(entity);
                    await _repository.DeleteAsync(son, cancellationToken);
                }
            }
            else
            {
                // 如果不级联删除，检查是否有子节点
                bool hasChildren = await _repository.HasChildNodesAsync(entity, cancellationToken);
                if (hasChildren)
                    throw DomainException.ValidationError("该节点下存在子节点，无法删除。如需删除，请设置级联删除选项");
            }

            // 删除当前节点
            BeforeDeleteEntity(entity);
            await _repository.DeleteAsync(entity, cancellationToken);

            return true;
        }

        /// <summary>
        /// 验证移动操作是否有效
        /// </summary>
        /// <param name="sourceId">源节点ID</param>
        /// <param name="targetId">目标节点ID</param>
        /// <param name="maxLevel">最大层级限制</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>验证结果</returns>
        public virtual async Task<DomainRuleCheckResult> ValidateMoveOperationAsync(
            TPrimaryKey sourceId,
            TPrimaryKey targetId,
            int maxLevel = 10,
            CancellationToken cancellationToken = default)
        {
            // 检查源节点是否存在
            var sourceNode = await _repository.GetAsync(sourceId, cancellationToken);
            if (sourceNode == null)
                return DomainRuleCheckResult.Fail($"源节点(ID:{sourceId})不存在");

            return await ValidateMoveOperationAsync(sourceNode, targetId, maxLevel, cancellationToken);
        }

        /// <summary>
        /// 验证移动操作是否有效
        /// </summary>
        /// <param name="sourceNode">源节点</param>
        /// <param name="targetId">目标节点ID</param>
        /// <param name="maxLevel">最大层级限制</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>验证结果</returns>
        public virtual async Task<DomainRuleCheckResult> ValidateMoveOperationAsync(
            TEntity sourceNode,
            TPrimaryKey targetId,
            int maxLevel = 10,
            CancellationToken cancellationToken = default)
        {
            // 如果目标ID是默认值，表示移动到根节点，这是合法的
            if (targetId!.Equals(default(TPrimaryKey)))
                return DomainRuleCheckResult.Ok();

            // 检查目标节点是否存在
            var targetNode = await _repository.GetAsync(targetId, cancellationToken);
            if (targetNode == null)
                return DomainRuleCheckResult.Fail($"目标节点(ID:{targetId})不存在");

            // 源节点不能是目标节点的父节点或祖先节点
            if (targetNode.NodePath.Contains($"{sourceNode.Id}"))
                return DomainRuleCheckResult.Fail("不能将节点移动到其子节点或后代节点下");

            // 校验目标节点层级是否已达到最大限制
            if (targetNode.NodePath.Split('#').Length >= maxLevel)
                return DomainRuleCheckResult.Fail($"目标节点已达到最大层级限制({maxLevel})，无法移动");

            return DomainRuleCheckResult.Ok();
        }

        /// <summary>
        /// 移动节点（包括子节点）到新位置
        /// </summary>
        /// <param name="entity">要移动的节点</param>
        /// <param name="newParentId">新的父节点ID</param>
        /// <param name="maxLevel">最大层级限制</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>操作结果</returns>
        public virtual async Task<DomainRuleCheckResult> MoveNodeAsync(TEntity entity, TPrimaryKey newParentId, int maxLevel = 10, CancellationToken cancellationToken = default)
        {
            // 验证移动操作是否有效
            var checkResult = await ValidateMoveOperationAsync(entity, newParentId, maxLevel, cancellationToken);
            if (!checkResult.IsComply)
                return checkResult;

            // 执行移动操作
            await ChangeParentIdAsync(entity, newParentId, maxLevel, cancellationToken);

            return DomainRuleCheckResult.Ok();
        }

        /// <summary>
        /// 移动节点（包括子节点）到新位置
        /// </summary>
        /// <param name="entityId">要移动的节点ID</param>
        /// <param name="newParentId">新的父节点ID</param>
        /// <param name="maxLevel">最大层级限制</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>操作结果</returns>
        public virtual async Task<DomainRuleCheckResult> MoveNodeAsync(TPrimaryKey entityId, TPrimaryKey newParentId, int maxLevel = 10, CancellationToken cancellationToken = default)
        {
            // 获取要移动的节点
            var entity = await _repository.GetAsync(entityId, cancellationToken);
            if (entity == null)
                return DomainRuleCheckResult.Fail($"节点(ID:{entityId})不存在");

            return await MoveNodeAsync(entity, newParentId, maxLevel, cancellationToken);
        }

        /// <summary>
        /// 修改节点的父节点ID
        /// </summary>
        /// <param name="entity">要修改的实体</param>
        /// <param name="newParentId">新的父节点ID</param>
        /// <param name="maxLevel">最大层级限制</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>操作任务</returns>
        protected virtual async Task ChangeParentIdAsync(
            TEntity entity,
            TPrimaryKey newParentId,
            int maxLevel = 10,
            CancellationToken cancellationToken = default)
        {
            string nodePath = entity.NodePath;

            //先更新当前节点
            TEntity? parentEntity = await GetTEntityAsync(newParentId, cancellationToken);
            ChangeEntityParent(entity, parentEntity, maxLevel);
            await _repository.UpdateAsync(entity, cancellationToken);

            var sons = await _repository.GetChildNodesRecursionAsync(nodePath, cancellationToken);
            //再更新子孙节点
            if (sons.Any())
            {
                foreach (TEntity son in sons)
                {
                    // 获取直接父节点
                    TPrimaryKey directParentId = son.ParentId;
                    var directParent = entity.Id!.Equals(son.ParentId) ? entity : sons.FirstOrDefault(f => f.Id!.Equals(son.ParentId));

                    if (directParent != null)
                    {
                        // 重新生成子节点的路径 - 基于直接父节点的新路径
                        ChangeEntityParent(son, directParent, maxLevel);
                        await _repository.UpdateAsync(son, cancellationToken);
                    }
                }
            }
        }

        /// <summary>
        /// 删除某个节点前的操作
        /// </summary>
        /// <param name="entity"></param>
        protected virtual void BeforeDeleteEntity(TEntity entity)
        {
        }

        /// <summary>
        /// 修改树节点的父节点
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="parentEntity"></param>
        /// <param name="maxLevel"></param>
        protected abstract void ChangeEntityParent(TEntity entity, TEntity? parentEntity, int maxLevel = 10);

        protected virtual string GetNodePath(TEntity? parentNode, TPrimaryKey thisId, int maxLevel = 10)
        {
            if (parentNode == null)
                return $"{thisId}";
            else
            {
                if (parentNode.NodePath.Split('#').Length >= maxLevel)
                    throw DomainException.ValidationError($"层级不允许超过{maxLevel}层！");
                return $"{parentNode.NodePath}#{thisId}";
            }
        }

        protected virtual async Task<TEntity?> GetTEntityAsync(TPrimaryKey parentId, CancellationToken cancellationToken = default)
        {
            if (parentId!.Equals(default(TPrimaryKey)))
                return null;
            else
                return await _repository.GetAsync(parentId, cancellationToken);
        }
    }
}